﻿namespace NKernel.Core.Impl
{
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Xml;

    using log4net;

    internal class ComponentOverrideDirective
    {
        #region Fields

        private const string ComponentElement = "Component";
        private const string ComponentOverrideXpath = "/Override/Components";

        private static readonly ILog Logger = LogManager.GetLogger(typeof (ComponentOverrideDirective));

        /// <summary>
        /// Key: component name, Value: fully-qualified implementing class name
        /// </summary>
        private readonly IDictionary<string, string> directive;

        #endregion Fields

        #region Constructors

        public ComponentOverrideDirective(string fileName)
        {
            directive = new Dictionary<string, string>();

            DoProcessFile(fileName);
        }

        #endregion Constructors

        #region Methods

        public string ComponentImplementation(string componentName)
        {
            string value = directive[componentName];

            if (String.IsNullOrEmpty(value))
            {
                value = string.Empty;
            }

            return value;
        }

        private void DoProcessFile(string file)
        {
            if (Logger.IsDebugEnabled)
            {
                Logger.DebugFormat("Processing Directive File: {0}", file);
            }

            var fileInfo = new FileInfo(file);

            if (fileInfo.Exists)
            {
                try
                {
                    var resourceStream = new FileStream(fileInfo.FullName, FileMode.Open);

                    DoProcessStream(resourceStream);
                }
                catch (Exception exception)
                {
                    Logger.Error("Problem encountered while opening stream to file: " +
                        fileInfo.FullName, exception);
                }
            }
            else
            {
                Logger.WarnFormat("Cannot find Directive File: {0}", file);
                return;
            }
        }

        private void DoProcessStream(Stream resourceStream)
        {
            var xmlDoc = new XmlDocument();
                try
                {
                    xmlDoc.Load(resourceStream);
                }
                catch (Exception exception)
                {
                    Logger.Error("Problem loading the Override Directive into the XML document", exception);
                }

                XmlNodeList nodes = xmlDoc.SelectNodes(ComponentOverrideXpath);

                if (nodes == null || nodes.Count == 0)
                {
                    Logger.Warn("Cannot find any override directives!");
                    return;
                }

                foreach (XmlNode node in nodes)
                {
                    XmlNode nodeComponent = node[ComponentElement];

                    if (nodeComponent == null)
                    {
                        continue;
                    }

                    string componentName = nodeComponent.Attributes["name"].InnerText;
                    string componentImpl = nodeComponent.Attributes["impl"].InnerText;

                    if (Logger.IsDebugEnabled)
                    {
                        Logger.DebugFormat("Override: Component Name-{0}, Impl-{1}", componentName, componentImpl);
                    }

                    directive.Add(componentName, componentImpl);
                }
        }

        #endregion Methods
    }
}